#pragma once
#include "message.hpp"
#include <vector>
#include <sstream>
#include <unordered_map>

namespace ns_log
{
    class FormatComponent
    {
    public:
        using ptr = std::shared_ptr<FormatComponent>;

        virtual ~FormatComponent() {}
        // 将消息内容流入out流当中
        virtual void format(std::ostream &out, const LogMessage &message) = 0;
    };

    class LevelComponent : public FormatComponent
    {
    public:
        virtual void format(std::ostream &out, const LogMessage &message)
        {
            out << LogLevel::LogLevel_Name(message._level);
        }
    };

    class BodyComponent : public FormatComponent
    {
    public:
        virtual void format(std::ostream &out, const LogMessage &message)
        {
            out << message._body;
        }
    };

    class FileComponent : public FormatComponent
    {
    public:
        virtual void format(std::ostream &out, const LogMessage &message)
        {
            out << message._file;
        }
    };

    class LineComponent : public FormatComponent
    {
    public:
        virtual void format(std::ostream &out, const LogMessage &message)
        {
            out << message._line;
        }
    };

    class NameComponent : public FormatComponent
    {
    public:
        virtual void format(std::ostream &out, const LogMessage &message)
        {
            out << message._logger_name;
        }
    };

    class LineBreakComponent : public FormatComponent
    {
    public:
        virtual void format(std::ostream &out, const LogMessage &message)
        {
            out << "\n";
        }
    };

    class TabComponent : public FormatComponent
    {
    public:
        virtual void format(std::ostream &out, const LogMessage &message)
        {
            out << "\t";
        }
    };

    class ThreadIdComponent : public FormatComponent
    {
    public:
        virtual void format(std::ostream &out, const LogMessage &message)
        {
            out << message._thread_id;
        }
    };

    class DateComponent : public FormatComponent
    {
    public:
        DateComponent(const std::string &format)
            : _format(format) {}

        virtual void format(std::ostream &out, const LogMessage &message)
        {
            const int max_size = _format.size() + 32;
            char buf[max_size] = {0};
            time_t now = message._time;
            struct tm *tm = localtime(&now);
            strftime(buf, max_size - 1, _format.c_str(), tm);
            out << buf;
        }

    private:
        std::string _format;
    };

    class OtherComponent : public FormatComponent
    {
    public:
        OtherComponent(const std::string &body)
            : _body(body) {}

        virtual void format(std::ostream &out, const LogMessage &message)
        {
            out << _body;
        }

    private:
        std::string _body;
    };

    /*
    如何解析

    遍历_pattern，维护一个非结构化字符串unformat_val ，如果当前字符不是%,则放入unformat_val的尾部，往后走一步

    否则，分为三种情况：
    （1）下一个字符是%，则将%放入unformat_val的尾部
    （2）下一个字符是d，则往后找} , 将{}里面的格式提出来，存为val, 后续要传递给createComponent作为参数
    （3）否则，就按普通的格式化字符来匹配

    一旦遇到格式化字符,最需要先把unformat_val字符串先抛入vec当中保存下来
    */

    class Formatter
    {
    public:
        using ptr = std::shared_ptr<Formatter>;
        // 日期[年月日 时分秒] [日志等级] [文件名:行号] [日志器名称] [线程ID] 消息主体 换行
        Formatter(const std::string &pattern = "[%d{%Y-%m-%d %H:%M:%S}] [%r] [%f:%l] [%g] [%i] %b%n")
            : _pattern(pattern)
        {
            if (!parse())
            {
                std::cout << "解析pattern失败!, pattern: " << _pattern << "\n";
                abort();
            }
        }

        void format(std::ostream &out, const LogMessage &message)
        {
            for (auto &elem : _components)
            {
                elem->format(out, message);
            }
        }

        std::string format(const LogMessage &message)
        {
            std::ostringstream oss;
            format(oss, message);
            return oss.str();
        }

        std::string getPattern()
        {
            return _pattern;
        }

    private:
        bool parse()
        {
            // 1. 解析字符串
            std::string unformat_val;
            size_t index = 0;
            size_t start = 0;
            std::vector<std::pair<std::string, std::string>> parse_ret;
            while (index < _pattern.size())
            {
                if (_pattern[index] != '%')
                {
                    unformat_val += _pattern[index++];
                }
                else if (index + 1 >= _pattern.size())
                {
                    std::cout << "解析失败，因为%后面没有字符，pattern：" << _pattern << "\n";
                    return false;
                }
                else if (_pattern[index + 1] == '%')
                {
                    unformat_val += '%';
                    index += 2;
                }
                else if (_pattern[index + 1] == 'd')
                {
                    if (!unformat_val.empty())
                    {
                        // 首先先将unformat_val放进去
                        parse_ret.push_back({"", unformat_val});
                        unformat_val.clear();
                    }
                    // 取出｛｝之内的二级格式
                    size_t start = _pattern.find('{', index + 2), end = _pattern.find('}', index + 2);
                    if (start == std::string::npos || end == std::string::npos)
                    {
                        std::cout << "解析失败，因为%d后面未找到{}，pattern：" << _pattern << "\n";
                        return false;
                    }
                    parse_ret.push_back({"d", _pattern.substr(start + 1, (end - 1) - (start + 1) + 1)});
                    index = end + 1;
                }
                else
                {
                    if (!unformat_val.empty())
                    {
                        // 首先先将unformat_val放进去
                        parse_ret.push_back({"", unformat_val});
                        unformat_val.clear();
                    }
                    parse_ret.push_back({_pattern.substr(index + 1, 1), ""});
                    index += 2;
                }
            }
            // 注意：非格式化字符是可以充底的，所以这里需要再次搞一下
            if (!unformat_val.empty())
            {
                // 首先先将unformat_val放进去
                parse_ret.push_back({"", unformat_val});
                unformat_val.clear();
            }
            // 2. 构造组成成分
            for (auto &elem : parse_ret)
            {
                _components.push_back(createComponent(elem.first, elem.second));
            }
            return true;
        }

        FormatComponent::ptr createComponent(const std::string &symbol, const std::string &val)
        {
            if (symbol == "d")
            {
                return std::make_shared<DateComponent>(val);
            }
            else if (symbol == "r")
            {
                return std::make_shared<LevelComponent>();
            }
            else if (symbol == "f")
            {
                return std::make_shared<FileComponent>();
            }
            else if (symbol == "l")
            {
                return std::make_shared<LineComponent>();
            }
            else if (symbol == "g")
            {
                return std::make_shared<NameComponent>();
            }
            else if (symbol == "i")
            {
                return std::make_shared<ThreadIdComponent>();
            }
            else if (symbol == "b")
            {
                return std::make_shared<BodyComponent>();
            }
            else if (symbol == "n")
            {
                return std::make_shared<LineBreakComponent>();
            }
            else if (symbol == "t")
            {
                return std::make_shared<TabComponent>();
            }
            else if (symbol == "")
            {
                return std::make_shared<OtherComponent>(val);
            }
            else
            {
                std::cout << "不存在该格式化字符: %" << symbol << "\n";
                abort();
                return FormatComponent::ptr(); // 返回一个空指针
            }
        }

        // 格式
        std::string _pattern;
        std::vector<FormatComponent::ptr> _components;
    };
}
